home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Packs / textedit / textedit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-03  |  15.6 KB  |  855 lines  |  [TEXT/????]

  1. /* Text Edit, high level routines */
  2.  
  3. #include "text.h"
  4.  
  5. void
  6. tereplace(tp, str)
  7.     TEXTEDIT *tp;
  8.     char *str;
  9. {
  10.     int len= strlen(str);
  11.     
  12.     if (len == 1 && teoptinschar(tp, (int) str[0]))
  13.         return;
  14.     
  15.     teinsert(tp, str, len);
  16. }
  17.  
  18. static
  19. teinschar(tp, c)
  20.     TEXTEDIT *tp;
  21.     int c;
  22. {
  23.     char cbuf[2];
  24.     
  25.     if (teoptinschar(tp, c))
  26.         return;
  27.     
  28.     cbuf[0]= c;
  29.     cbuf[1]= EOS;
  30.     teinsert(tp, cbuf, 1);
  31. }
  32.  
  33. /* Interfaces for wchange and wscroll that clip to the viewing rectangle */
  34.  
  35. static void
  36. techange(tp, left, top, right, bottom)
  37.     TEXTEDIT *tp;
  38.     int left, top, right, bottom;
  39. {
  40.     if (tp->viewing) {
  41.         CLIPMIN(left, tp->vleft);
  42.         CLIPMIN(top, tp->vtop);
  43.         CLIPMAX(right, tp->vright);
  44.         CLIPMAX(bottom, tp->vbottom);
  45.     }
  46.     wchange(tp->win, left, top, right, bottom);
  47. }
  48.  
  49. static void
  50. tescroll(tp, left, top, right, bottom, dh, dv)
  51.     TEXTEDIT *tp;
  52.     int left, top, right, bottom;
  53.     int dh, dv;
  54. {
  55.     if (tp->viewing) {
  56.         CLIPMIN(left, tp->vleft);
  57.         CLIPMIN(top, tp->vtop);
  58.         CLIPMAX(right, tp->vright);
  59.         CLIPMAX(bottom, tp->vbottom);
  60.     }
  61.     wscroll(tp->win, left, top, right, bottom, dh, dv);
  62.     /* XXX Should call wchange for bits scrolled in from outside view? */
  63. }
  64.  
  65. /* Optimization for the common case insert char.
  66.    Assumes text measurement is additive. */
  67.  
  68. static
  69. tesetoptdata(tp)
  70.     TEXTEDIT *tp;
  71. {
  72.     lineno i;
  73.     bufpos k, pos, end;
  74.     
  75.     zcheck();
  76.     zassert(tp->foclen == 0);
  77.     
  78.     pos= zaddgap(tp->foc);
  79.     tp->opt_i= i= tewhichline(tp, pos, FALSE);
  80.     tp->opt_h= tp->left + tetextwidth(tp, tp->start[i], pos);
  81.     tp->opt_v= tp->top + i*tp->vspace;
  82.     end= tp->start[i+1];
  83.     if (end > pos && zcharbefore(end) == EOL)
  84.         zdecr(&end);
  85.     while (end > pos && zcharbefore(end) == ' ')
  86.         zdecr(&end);
  87.     for (k= pos; k < end; zincr(&k)) {
  88.         if (zcharat(k) == '\t')
  89.             break;
  90.     }
  91.     if (k < end) {
  92.         tp->opt_end=
  93.             tp->left + tetextwidth(tp, tp->start[i], znext(k));
  94.         tp->opt_avail= tp->opt_end -
  95.             (tp->left + tetextwidth(tp, tp->start[i], k));
  96.     }
  97.     else {
  98.         tp->opt_end= tp->right;
  99.         tp->opt_avail= tp->width - tetextwidth(tp, tp->start[i], end);
  100.     }
  101.     if (tp->start[i] > 0 && zcharbefore(tp->start[i]) != EOL) {
  102.         tp->opt_in_first_word= TRUE;
  103.         for (k= tp->start[i]; k < pos; zincr(&k)) {
  104.             if (isspace(zcharat(k))) {
  105.                 tp->opt_in_first_word= FALSE;
  106.                 break;
  107.             }
  108.         }
  109.     }
  110.     else
  111.         tp->opt_in_first_word= FALSE;
  112.     tp->opt_valid= TRUE;
  113. }
  114.  
  115. static bool
  116. teoptinschar(tp, c)
  117.     TEXTEDIT *tp;
  118.     int c;
  119. {
  120.     int w;
  121.     
  122.     if (tp->foclen != 0 || c == EOL || c == '\t' || tp->focprev)
  123.         return FALSE;
  124.     if (!tp->opt_valid)
  125.         tesetoptdata(tp);
  126.     if (c == ' ' && tp->opt_in_first_word)
  127.         return FALSE;
  128.     w= wcharwidth(c);
  129.     if (w >= tp->opt_avail)
  130.         return FALSE;
  131.     
  132.     temovegapto(tp, tp->foc);
  133.     if (tp->gaplen < 1)
  134.         tegrowgapby(tp, 1+RESERVE);
  135.     if (tp->start[tp->opt_i] == zgapend)
  136.         tp->start[tp->opt_i]= tp->gap;
  137.     ++tp->gap;
  138.     --tp->gaplen;
  139.     tp->buf[tp->foc]= c;
  140.     ++tp->foc;
  141.     
  142.     tp->opt_avail -= w;
  143.     if (tp->active)
  144.         wnocaret(tp->win);
  145.     tescroll(tp,
  146.         tp->opt_h, tp->opt_v,
  147.         tp->opt_end, tp->opt_v + tp->vspace,
  148.         w, 0);
  149.     wbegindrawing(tp->win);
  150.     if (tp->viewing)
  151.         wcliprect(tp->vleft, tp->vtop, tp->vright, tp->vbottom);
  152.     wdrawchar(tp->opt_h, tp->opt_v, c);
  153.     wenddrawing(tp->win);
  154.     tp->opt_h += w;
  155.     if (tp->active) {
  156.         if (!tp->viewing ||
  157.             tp->vleft <= tp->opt_h &&
  158.             tp->opt_h <= tp->vright &&
  159.             tp->vtop <= tp->opt_v &&
  160.             tp->opt_v + tp->vspace <= tp->vbottom) {
  161.             wsetcaret(tp->win, tp->opt_h, tp->opt_v);
  162.             wshow(tp->win,
  163.                   tp->opt_h, tp->opt_v,
  164.                   tp->opt_h, tp->opt_v + tp->vspace);
  165.         }
  166.         else
  167.             wnocaret(tp->win);
  168.     }
  169.     tp->aim= tp->opt_h;
  170.     
  171.     return TRUE;
  172. }
  173.  
  174. static
  175. teinsert(tp, str, len)
  176.     TEXTEDIT *tp;
  177.     char *str;
  178.     int len;
  179. {
  180.     focpos oldfoc= tp->foc;
  181.     
  182.     tehidefocus(tp);
  183.     temovegapto(tp, zfocend);
  184.     tp->gap= tp->foc;
  185.     tp->gaplen += tp->foclen;
  186.     teemptygap(tp);
  187.     tp->foclen= 0;
  188.     if (tp->gaplen < len)
  189.         tegrowgapby(tp, len-tp->gaplen+RESERVE);
  190.     strncpy(tp->buf+tp->gap, str, len);
  191.     tp->gap += len;
  192.     tp->gaplen -= len;
  193.     tp->foc += len;
  194.     terecompute(tp, zaddgap(oldfoc), zaddgap(tp->foc));
  195. }
  196.  
  197. static int lasteol;    /* Optimization trick for teendofline */
  198.  
  199. static
  200. terecompute(tp, first, last)
  201.     TEXTEDIT *tp;
  202.     int first, last;
  203. {
  204.     lineno i;
  205.     lineno chfirst, chlast; /* Area to pass to wchange */
  206.     lineno shift= 0; /* Lines to shift down (negative: up) */
  207.     vcoord newbottom;
  208.     
  209.     tp->start[0]= zaddgap(0);
  210.     
  211.     i= 2;
  212.     while (i <= tp->nlines && tp->start[i] < first)
  213.         ++i;
  214.     i -= 2;
  215.     chfirst= tp->nlines;
  216.     chlast= i;
  217.     lasteol= -1;
  218.     
  219.     /* TO DO: scroll up/down if inserting/deleting lines */
  220.     
  221.     for (;; ++i) {
  222.         bufpos end= teendofline(tp, tp->start[i]);
  223.         bool unchanged= (i < tp->nlines && end == tp->start[i+1]);
  224.         if (!unchanged)
  225.             shift += tesetstart(tp, i+1, end, last);
  226.         if (!(unchanged && end < first)) {
  227.             if (i < chfirst)
  228.                 chfirst= i;
  229.             chlast= i+1;
  230.         }
  231.         if (end >= tp->buflen) {
  232.             if (end > tp->start[i] && zcharbefore(end) == EOL)
  233.                 continue;
  234.             else
  235.                 break;
  236.         }
  237.         if (unchanged && end > last) {
  238.             i= tp->nlines-1;
  239.             break;
  240.         }
  241.     }
  242.     
  243.     zassert(tp->nlines > i);
  244.     
  245.     if (tp->drawing) {
  246.         if (shift != 0) {
  247.             lineno k= chlast;
  248.             if (shift > 0)
  249.                 k -= shift;
  250.             tescroll(tp,
  251.                 tp->left, tp->top + k*tp->vspace,
  252.                 tp->right, tp->top + tp->nlines*tp->vspace,
  253.                 0, shift*tp->vspace);
  254.         }
  255.         
  256.         techange(tp,
  257.             tp->left, tp->top + chfirst*tp->vspace,
  258.             tp->right, tp->top + chlast*tp->vspace);
  259.     }
  260.     
  261.     tp->nlines= i+1;
  262.     newbottom= tp->top + tp->vspace*tp->nlines;
  263.     if (newbottom < tp->bottom)
  264.         techange(tp,
  265.             tp->left, newbottom, tp->right, tp->bottom);
  266.     tp->bottom= newbottom;
  267.     tp->aim= UNDEF;
  268.     tp->focprev= FALSE;
  269.     if (tp->drawing)
  270.         tesetcaret(tp);
  271.     
  272.     zcheck();
  273. }
  274.  
  275. static int
  276. tesetstart(tp, i, pos, last)
  277.     register TEXTEDIT *tp;
  278.     register lineno i;
  279.     bufpos pos, last;
  280. {
  281.     if (i > tp->nlines) {
  282.         tp->nlines= i;
  283.         if (tp->nlines >= tp->nstart) {
  284.             tp->nstart= tp->nlines + STARTINCR;
  285.             tp->start= (bufpos*)zrealloc((char*)tp->start,
  286.                 tp->nstart*sizeof(int));
  287.         }
  288.         tp->start[i]= pos;
  289.         return 0;
  290.     }
  291.     else {
  292.         lineno shift= 0;
  293.         lineno k;
  294.         for (k= i; k < tp->nlines; ++k) {
  295.             if (tp->start[k] > pos)
  296.                 break;
  297.         }
  298.         shift= k-1 - i;
  299.         /* start[k] should really be start[i+1] */
  300.         if (shift < 0 && tp->start[k] >= last) { /* Insert one */
  301.             ++tp->nlines;
  302.             if (tp->nlines >= tp->nstart) {
  303.                 tp->nstart= tp->nlines + STARTINCR;
  304.                 tp->start= (int*)zrealloc((char*)tp->start,
  305.                     tp->nstart*sizeof(int));
  306.             }
  307.             for (k= tp->nlines; k > i; --k)
  308.                 tp->start[k]= tp->start[k-1];
  309.         }
  310.         else if (shift > 0 && pos >= last) { /* Delete some */
  311.             for (; k <= tp->nlines; ++k)
  312.                 tp->start[k-shift]= tp->start[k];
  313.             tp->nlines -= shift;
  314.             if (tp->nlines < tp->nstart - STARTINCR) {
  315.                 tp->nstart= tp->nlines+1;
  316.                 tp->start= (int*)zrealloc((char*)tp->start,
  317.                     tp->nstart*sizeof(int));
  318.             }
  319.         }
  320.         else
  321.             shift= 0; /* Don't shift (yet) */
  322.         tp->start[i]= pos;
  323.         return -shift;
  324.     }
  325. }
  326.  
  327. static int
  328. teendofline(tp, pos)
  329.     TEXTEDIT *tp;
  330.     bufpos pos;
  331. {
  332.     bufpos end= tp->buflen;
  333.     bufpos k;
  334.     
  335.     /* Find first EOL if any */
  336.     if (lasteol >= pos)
  337.         k= lasteol;
  338.     else {
  339.         for (k= pos; k < end && zcharat(k) != EOL; zincr(&k))
  340.             ;
  341.         lasteol= k;
  342.     }
  343.     
  344.     end= tetextbreak(tp, pos, k, tp->width);
  345.     
  346.     /* Extend with any spaces immediately following end */
  347.     for (; end < tp->buflen && zcharat(end) == ' '; zincr(&end))
  348.         ;
  349.     
  350.     if (end < tp->buflen) {
  351.         /* Extend with immediately following EOL */
  352.         if (zcharat(end) == EOL)
  353.             zincr(&end);
  354.         else {
  355.             /* Search back for space before last word */
  356.             for (k= end; zdecr(&k) >= pos && !isspace(zcharat(k)); )
  357.                 ;
  358.             
  359.             if (k >= pos)
  360.                 end= znext(k);
  361.         }
  362.     }
  363.  
  364.     /* Each line must be at least one character long,
  365.        otherwise a very narrow text-edit box would cause
  366.        the size calculation to last forever */
  367.     if (end == pos && end < tp->buflen)
  368.         zincr(&end);
  369.     
  370.     return end;
  371. }
  372.  
  373. bool
  374. teevent(tp, e)
  375.     TEXTEDIT *tp;
  376.     EVENT *e;
  377. {
  378.     if (e->window != tp->win)
  379.         return FALSE;
  380.     
  381.     switch (e->type) {
  382.     
  383.     case WE_CHAR:
  384.         teinschar(tp, e->u.character);
  385.         break;
  386.     
  387.     case WE_COMMAND:
  388.         switch (e->u.command) {
  389.         case WC_BACKSPACE:
  390.             tebackspace(tp);
  391.             break;
  392.         case WC_RETURN:
  393.             teinschar(tp, EOL);
  394.             break;
  395.         case WC_TAB:
  396.             teinschar(tp, '\t');
  397.             break;
  398.         case WC_LEFT:
  399.         case WC_RIGHT:
  400.         case WC_UP:
  401.         case WC_DOWN:
  402.             tearrow(tp, e->u.command);
  403.             break;
  404.         default:
  405.             return FALSE;
  406.         }
  407.         break;
  408.     
  409.     case WE_MOUSE_DOWN:
  410.         {
  411.             int h= e->u.where.h, v= e->u.where.v;
  412.             if (tp->viewing) {
  413.                 if (h < tp->vleft || h > tp->vright ||
  414.                     v < tp->vtop || v > tp->vbottom)
  415.                     return FALSE;
  416.             }
  417.             else {
  418.                 if (h < tp->left || h > tp->right ||
  419.                     v < tp->top || v > tp->bottom)
  420.                     return FALSE;
  421.             }
  422.             teclicknew(tp, h, v,
  423.                    e->u.where.button == 3 ||
  424.                    (e->u.where.mask & WM_SHIFT),
  425.                    e->u.where.clicks > 1);
  426.         }
  427.         break;
  428.     
  429.     case WE_MOUSE_MOVE:
  430.     case WE_MOUSE_UP:
  431.         if (!tp->mdown)
  432.             return FALSE;
  433.         teclicknew(tp, e->u.where.h, e->u.where.v, TRUE, tp->dclick);
  434.         if (e->type == WE_MOUSE_UP)
  435.             tp->mdown= FALSE;
  436.         break;
  437.     
  438.     case WE_DRAW:
  439.         wbegindrawing(tp->win);
  440.         tedrawnew(tp, e->u.area.left, e->u.area.top,
  441.                 e->u.area.right, e->u.area.bottom);
  442.         wenddrawing(tp->win);
  443.         break;
  444.     
  445.     default:
  446.         return FALSE;
  447.     
  448.     }
  449.     
  450.     /* If broke out of switch: */
  451.     return TRUE;
  452. }
  453.  
  454. void
  455. tearrow(tp, code)
  456.     TEXTEDIT *tp;
  457.     int code;
  458. {
  459.     lineno i;
  460.     bufpos pos;
  461.     
  462.     tehidefocus(tp);
  463.     
  464.     switch (code) {
  465.     
  466.     case WC_LEFT:
  467.         if (tp->foclen != 0)
  468.             tp->foclen= 0;
  469.         else {
  470.             if (tp->foc > 0)
  471.                 --tp->foc;
  472.             else
  473.                 wfleep();
  474.         }
  475.         tp->aim= UNDEF;
  476.         tp->focprev= FALSE;
  477.         break;
  478.     
  479.     case WC_RIGHT:
  480.         if (tp->foclen != 0) {
  481.             tp->foc += tp->foclen;
  482.             tp->foclen= 0;
  483.         }
  484.         else {
  485.             if (tp->foc < tp->buflen-tp->gaplen)
  486.                 ++tp->foc;
  487.             else
  488.                 wfleep();
  489.         }
  490.         tp->aim= UNDEF;
  491.         tp->focprev= FALSE;
  492.         break;
  493.     
  494.     /* TO DO: merge the following two cases */
  495.     
  496.     case WC_UP:
  497.         if (tp->foclen > 0)
  498.             tp->foclen= 0;
  499.         else {
  500.             pos= zaddgap(tp->foc);
  501.             i= tewhichline(tp, pos, (bool) tp->focprev);
  502.             if (i <= 0)
  503.                 wfleep();
  504.             else {
  505.                 if (tp->aim == UNDEF)
  506.                     tp->aim= tp->left + tetextwidth(tp,
  507.                         tp->start[i], pos);
  508.                 --i;
  509.                 pos= tetextround(tp, i, tp->aim);
  510.                 tp->foc= zsubgap(pos);
  511.                 tp->focprev= (pos == tp->start[i+1]);
  512.             }
  513.         }
  514.         break;
  515.     
  516.     case WC_DOWN:
  517.         if (tp->foclen > 0) {
  518.             tp->foc += tp->foclen;
  519.             tp->foclen= 0;
  520.         }
  521.         else {
  522.             pos= zaddgap(tp->foc);
  523.             i= tewhichline(tp, pos, (bool) tp->focprev);
  524.             if (i+1 >= tp->nlines)
  525.                 wfleep();
  526.             else {
  527.                 if (tp->aim == UNDEF)
  528.                     tp->aim= tp->left + tetextwidth(tp,
  529.                         tp->start[i], pos);
  530.                 ++i;
  531.                 pos= tetextround(tp, i, tp->aim);
  532.                 tp->foc= zsubgap(pos);
  533.                 tp->focprev= (pos == tp->start[i+1]);
  534.             }
  535.         }
  536.         break;
  537.     
  538.     default:
  539.         dprintf("tearrow: bad code %d", code);
  540.         break;
  541.         
  542.     }
  543.     tesetcaret(tp);
  544. }
  545.  
  546. void
  547. tebackspace(tp)
  548.     TEXTEDIT *tp;
  549. {
  550.     if (tp->foclen == 0) {
  551.         if (tp->foc == 0) {
  552.             wfleep();
  553.             return;
  554.         }
  555.         --tp->foc;
  556.         tp->foclen= 1;
  557.     }
  558.     teinsert(tp, "", 0);
  559. }
  560.  
  561. bool
  562. teclicknew(tp, h, v, extend, dclick)
  563.     TEXTEDIT *tp;
  564.     coord h, v;
  565.     bool extend, dclick;
  566. {
  567.     lineno i;
  568.     bufpos pos;
  569.     focpos f;
  570.     
  571.     tp->dclick= dclick;
  572.     pos= tewhereis(tp, h, v, &i);
  573.     f= zsubgap(pos);
  574.     if (extend) {
  575.         if (!tp->mdown) {
  576.             tp->mdown= TRUE;
  577.             if (f - tp->foc < tp->foc + tp->foclen - f)
  578.                 tp->anchor= tp->foc + tp->foclen;
  579.             else
  580.                 tp->anchor= tp->foc;
  581.             tp->anchor2= tp->anchor;
  582.         }
  583.         if (f >= tp->anchor) {
  584.             if (dclick)
  585.                 f= tewordend(tp, f);
  586.             techangefocus(tp, tp->anchor, f);
  587.         }
  588.         else {
  589.             if (dclick)
  590.                 f= tewordbegin(tp, f);
  591.             techangefocus(tp, f, tp->anchor2);
  592.         }
  593.     }
  594.     else {
  595.         tp->mdown= TRUE;
  596.         tp->anchor= tp->anchor2= f;
  597.         if (dclick) {
  598.             tp->anchor= tewordbegin(tp, tp->anchor);
  599.             tp->anchor2= tewordend(tp, f);
  600.         }
  601.         techangefocus(tp, tp->anchor, tp->anchor2);
  602.     }
  603.     tp->aim= UNDEF;
  604.     tp->focprev= (tp->foclen == 0 && pos == tp->start[i+1]);
  605.     tesetcaret(tp);
  606.     return TRUE;
  607. }
  608.  
  609. /* Return f, 'rounded down' to a word begin */
  610.  
  611. static int
  612. tewordbegin(tp, f)
  613.     TEXTEDIT *tp;
  614.     int f;
  615. {
  616.     f= zaddgap(f);
  617.     for (;;) {
  618.         if (f == 0 || isspace(zcharbefore(f)))
  619.             break;
  620.         zdecr(&f);
  621.     }
  622.     return zsubgap(f);
  623. }
  624.  
  625. /* Ditto to word end */
  626.  
  627. static int
  628. tewordend(tp, f)
  629.     TEXTEDIT *tp;
  630.     int f;
  631. {
  632.     f= zaddgap(f);
  633.     for (;;) {
  634.         if (f >= tp->buflen || isspace(zcharat(f)))
  635.             break;
  636.         zincr(&f);
  637.     }
  638.     return zsubgap(f);
  639. }
  640.  
  641. int
  642. tegetleft(tp)
  643.     TEXTEDIT *tp;
  644. {
  645.     return tp->left;
  646. }
  647.  
  648. int
  649. tegettop(tp)
  650.     TEXTEDIT *tp;
  651. {
  652.     return tp->top;
  653. }
  654.  
  655. int
  656. tegetright(tp)
  657.     TEXTEDIT *tp;
  658. {
  659.     return tp->right;
  660. }
  661.  
  662. int
  663. tegetbottom(tp)
  664.     TEXTEDIT *tp;
  665. {
  666.     return tp->bottom;
  667. }
  668.  
  669. void
  670. temove(tp, left, top, width)
  671.     TEXTEDIT *tp;
  672.     coord left, top, width;
  673. {
  674.     temovenew(tp, left, top, left+width, top + tp->nlines*tp->vspace);
  675. }
  676.  
  677. /*ARGSUSED*/
  678. void
  679. temovenew(tp, left, top, right, bottom)
  680.     TEXTEDIT *tp;
  681.     int left, top, right, bottom;
  682. {
  683.     int oldheight= tp->bottom - tp->top;
  684.     tp->left= left;
  685.     tp->top= top;
  686.     tp->right= right;
  687.     tp->bottom= tp->top + oldheight;
  688.     if (right - left != tp->width) {
  689.         tp->width= right - left;
  690.         tp->nlines= 0; /* Experimental! */
  691.         terecompute(tp, 0, tp->buflen);
  692.     }
  693. }
  694.  
  695. void
  696. tesetview(tp, left, top, right, bottom)
  697.     TEXTEDIT *tp;
  698.     int left, top, right, bottom;
  699. {
  700.     tp->viewing= TRUE;
  701.     tp->vleft= left;
  702.     tp->vtop= top;
  703.     tp->vright= right;
  704.     tp->vbottom= bottom;
  705. }
  706.  
  707. void
  708. tenoview(tp)
  709.     TEXTEDIT *tp;
  710. {
  711.     tp->viewing= FALSE;
  712. }
  713.  
  714. void
  715. tesetfocus(tp, foc1, foc2)
  716.     TEXTEDIT *tp;
  717.     focpos foc1, foc2;
  718. {
  719.     if (foc1 > tp->buflen - tp->gaplen)
  720.         foc1= tp->buflen - tp->gaplen;
  721.     if (foc2 > tp->buflen - tp->gaplen)
  722.         foc2= tp->buflen - tp->gaplen;
  723.     if (foc1 < 0)
  724.         foc1= 0;
  725.     if (foc2 < foc1)
  726.         foc2= foc1;
  727.     techangefocus(tp, foc1, foc2);
  728.     tp->aim= UNDEF;
  729.     tp->focprev= FALSE;
  730.     tesetcaret(tp);
  731. }
  732.  
  733. int
  734. tegetfoc1(tp)
  735.     TEXTEDIT *tp;
  736. {
  737.     return tp->foc;
  738. }
  739.  
  740. int
  741. tegetfoc2(tp)
  742.     TEXTEDIT *tp;
  743. {
  744.     return tp->foc + tp->foclen;
  745. }
  746.  
  747. int
  748. tegetnlines(tp)
  749.     TEXTEDIT *tp;
  750. {
  751.     return tp->nlines;
  752. }
  753.  
  754. char *
  755. tegettext(tp)
  756.     TEXTEDIT *tp;
  757. {
  758.     temovegapto(tp, tp->buflen - tp->gaplen);
  759.     if (tp->gaplen < 1)
  760.         tegrowgapby(tp, 1+RESERVE);
  761.     tp->buf[tp->gap]= EOS;
  762.     return tp->buf;
  763. }
  764.  
  765. int
  766. tegetlen(tp)
  767.     TEXTEDIT *tp;
  768. {
  769.     return tp->buflen - tp->gaplen;
  770. }
  771.  
  772. void
  773. tesetbuf(tp, buf, buflen)
  774.     TEXTEDIT *tp;
  775.     char *buf;
  776.     int buflen;
  777. {
  778.     bool drawing= tp->drawing;
  779.     
  780.     if (buf == NULL || buflen < 0)
  781.         return;
  782.     if (drawing)
  783.         techange(tp, tp->left, tp->top, tp->right, tp->bottom);
  784.     free(tp->buf);
  785.     tp->buf= buf;
  786.     tp->buflen= buflen;
  787.     tp->foc= tp->foclen= tp->gap= tp->gaplen= 0;
  788.     tp->drawing= FALSE;
  789.     terecompute(tp, 0, tp->buflen);
  790.     if (drawing) {
  791.         tp->drawing= TRUE;
  792.         techange(tp, tp->left, tp->top, tp->right, tp->bottom);
  793.     }
  794. }
  795.  
  796.  
  797. /* The following paragraph-drawing routines are experimental.
  798.    They cannibalize on the existing text-edit code,
  799.    which makes it trivial to ensure the lay-out is the same,
  800.    but causes overhead to initialize a text-edit struct.
  801.    The flag 'drawing' has been added to the textedit struct,
  802.    which suppresses calls to tesetcaret, wchange and wscroll
  803.    from tesetup and terecompute.
  804.    It doesn't suppress actual drawing, which only occurs when
  805.    tedraw is called.
  806.    Note -- this could be optimized, but it is infrequently,
  807.    so I don't care until I get complaints. */
  808.  
  809. /* Draw a paragraph of text, exactly like tedraw would draw it.
  810.    Parameters are the top left corner, the width, the text and its length.
  811.    Return value is the v coordinate of the bottom line.
  812.    An empty string is drawn as one blank line. */
  813.  
  814. int
  815. wdrawpar(left, top, text, width)
  816.     int left, top;
  817.     char *text;
  818.     int width;
  819. {
  820.     return _wdrawpar(left, top, text, width, TRUE);
  821. }
  822.  
  823. /* Measure the height of a paragraph of text, when drawn with wdrawpar. */
  824.  
  825. int
  826. wparheight(text, width)
  827.     char *text;
  828.     int width;
  829. {
  830.     return _wdrawpar(0, 0, text, width, FALSE);
  831. }
  832.  
  833. /* Routine to do the dirty work for the above two.
  834.    Size calculations are implemented by going through the normal
  835.    routine but suppressing the actual drawing. */
  836.  
  837. static int
  838. _wdrawpar(left, top, text, width, draw)
  839.     int left, top;
  840.     char *text;
  841.     int width;
  842.     bool draw;
  843. {
  844.     TEXTEDIT *tp= tesetup((WINDOW*)NULL, left, top, left+width, top, FALSE);
  845.     int v;
  846.     
  847.     tesetbuf(tp, text, strlen(text));
  848.     if (draw)
  849.         tedraw(tp);
  850.     v= tegetbottom(tp);
  851.     tp->buf= NULL;
  852.     tefree(tp);
  853.     return v;
  854. }
  855.